#include "serial.h"

static inline uint32_t fifo_length(struct serial_fifo *fifo)
{
    uint32_t length = (fifo->put_index >= fifo->get_index)? (fifo->put_index - fifo->get_index):
                    (fifo->buf_size - (fifo->get_index - fifo->put_index));

	return length;
}

/**@brief Put one byte to the FIFO. */
static inline void fifo_put(struct serial_fifo * fifo, uint8_t ch)
{
	fifo->buffer[fifo->put_index] = ch;
	fifo->put_index += 1;
	if (fifo->put_index >= fifo->buf_size)
		fifo->put_index = 0;

	/* if the next position is read index, discard this 'read char' */
	//写指针已经赶上读指针了,FIFO满了
	if (fifo->put_index == fifo->get_index){
		fifo->get_index += 1;	//丢弃未读的值
		fifo->is_full = true;
		if (fifo->get_index >= fifo->buf_size) fifo->get_index = 0;
	}
}

uint32_t fifo_write(struct serial_fifo * p_fifo, uint8_t const * p_byte_array, uint32_t * p_size)
{
	//要写的字节数比FIFO的容量还多, 那么丢弃多出的部分,并返回实际写的大小
	if(*p_size > p_fifo->buf_size){
        *p_size = p_fifo->buf_size;
	}

    // 万一没传入要写的缓存, 直接返回
    if (p_byte_array == NULL){
        return 1;
    }

	//写入fifo
	for(int i = 0; i < *p_size; i++){
		 fifo_put(p_fifo, p_byte_array[i]);
	}

    return 0;
}

/**@brief Get one byte from the FIFO. */
// return true no data
bool fifo_get(struct serial_fifo *fifo, uint8_t *data)
{
	int ch;

	/* there's no data: */
	if ((fifo->get_index == fifo->put_index) && (fifo->is_full == false))
		return true;

	/* otherwise there's the data: */
	ch = fifo->buffer[fifo->get_index];
	fifo->get_index += 1;
	if (fifo->get_index >= fifo->buf_size)
		fifo->get_index = 0;

	if (fifo->is_full == true)	//如果原来满了,任意读出一个字节即可不满
		fifo->is_full = false;

	*data = ch & 0xff;
	data ++;

	return false;
}

/** Leaves the minimum of the two 32-bit arguments */
#define MIN(a, b) ((a) < (b) ? (a) : (b))
//从fifo读出一段数据,若fifo比需求的长度还小,则只读fifo长度
//正常返回0
uint32_t fifo_read(struct serial_fifo * p_fifo, uint8_t * p_byte_array, uint32_t * p_size)
{

    const uint32_t byte_count    = fifo_length(p_fifo);
    const uint32_t requested_len = (*p_size);
    uint32_t       read_size     = MIN(requested_len, byte_count);

    (*p_size) = byte_count;

    // Check if the FIFO is empty.
    if (byte_count == 0){
        return 1;
    }

    // Check if application has requested only the size.
    if (p_byte_array == NULL){
        return 1;
    }

	for(int i = 0; i < read_size; i++){
		fifo_get(p_fifo, &p_byte_array[i]);
	}

    (*p_size) = read_size;

    return 0;
}

//uint32_t app_uart_write(uint8_t *p_byte_array,  uint32_t *p_size)
//{
//    uint32_t err_code;
//	err_code = fifo_write(&uart_tx_fifo, p_byte_array, p_size);
//
//    if (err_code == 0){
//		// DMA 不忙才可发送
////        if (HAL_DMA_GetState(&UART1TxDMA_Handler) != HAL_DMA_STATE_BUSY){
////			//有问题, DMA 的缓存不一定有那么大
////			uint32_t send_len = *p_size;
////			if(send_len > DMA_TX_BUF_LEN)	//如果写入fifo的比DMA 缓存还大,那么只能发送DMA缓存的大小,剩余部分在DMA发送完中断中继续发
////				send_len = DMA_TX_BUF_LEN;
////
////			if (fifo_read(&uart_tx_fifo, UART1_Handler.pTxBuffPtr, &send_len) == 0){				//将fifo中的数据读入DMA缓存
//////				HAL_UART_Transmit_DMA(&UART1_Handler, UART1_Handler.pTxBuffPtr, send_len); 			//启动传输,
////            }
////
////        }
//    }
//    return err_code;
//}


//#endif

/*
 * Serial poll routines
 */
static inline int _serial_poll_rx(struct pt_serial_device *serial, uint8_t *data, int length)
{
//    int size;
//
//    PT_ASSERT(serial != PT_NULL);
//    size = length;
//
//    struct serial_fifo *rx_fifo = serial->serial_rx;
//    if(rx_fifo != PT_NULL){
//        fifo_read(rx_fifo, data, &size);
//    }else{
//        PT_DEBUG_LOG(PT_LOG_LEVEL_DEBUG, ("_serial_poll_rx no rx_fifo\n") );
//    }
//
//
//    // 返回真正读到的长度
//    return size;
    return 0;
}
//
static inline int _serial_poll_tx(struct pt_serial_device *serial, const uint8_t *data, int length)
{
    int size;
    PT_ASSERT(serial != PT_NULL);

    size = length;
    // 阻塞式的发送
    while (length){
        serial->ops->putc(serial, *data);
        ++ data; -- length;
    }

    return size - length;
}

///*
// * Serial interrupt routines
// */
//rt_inline int _serial_int_rx(struct pt_serial_device *serial, rt_uint8_t *data, int length)
//{
//    int size;
//    struct pt_serial_rx_fifo* rx_fifo;
//
//    PT_ASSERT(serial != PT_NULL);
//    size = length;
//
//    rx_fifo = (struct pt_serial_rx_fifo*) serial->serial_rx;
//    PT_ASSERT(rx_fifo != PT_NULL);
//
//    /* read from software FIFO */
//    while (length)
//    {
//        int ch;
//        rt_base_t level;
//
//        /* disable interrupt */
//        level = rt_hw_interrupt_disable();
//
//        /* there's no data: */
//        if ((rx_fifo->get_index == rx_fifo->put_index) && (rx_fifo->is_full == RT_FALSE))
//        {
//            /* no data, enable interrupt and break out */
//            rt_hw_interrupt_enable(level);
//            break;
//        }
//
//        /* otherwise there's the data: */
//        ch = rx_fifo->buffer[rx_fifo->get_index];
//        rx_fifo->get_index += 1;
//        if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
//
//        if (rx_fifo->is_full == RT_TRUE)
//        {
//            rx_fifo->is_full = RT_FALSE;
//        }
//
//        /* enable interrupt */
//        rt_hw_interrupt_enable(level);
//
//        *data = ch & 0xff;
//        data ++; length --;
//    }
//
//    return size - length;
//}

static inline int _serial_int_tx(struct pt_serial_device *serial, const uint8_t *data, int length)
{
    //中断方式模拟比较难
//    int size;
//    struct pt_serial_tx_fifo *tx;
//
//    PT_ASSERT(serial != PT_NULL);
//
//    size = length;
//    tx = (struct pt_serial_tx_fifo*) serial->serial_tx;
//    PT_ASSERT(tx != PT_NULL);
//
//
//        serial->ops->putc(serial, *(char*)data);
//        data ++; length --;
//
//
//    return size - length;
    PT_DEBUG_LOG(PT_LOG_LEVEL_DEBUG, ("not implement\n") );
    return 0;
}

/*
 * Serial DMA routines
 */
//rt_inline int _serial_dma_rx(struct pt_serial_device *serial, rt_uint8_t *data, int length)
//{
//    rt_base_t level;
//
//    PT_ASSERT((serial != PT_NULL) && (data != PT_NULL));
//
//    level = rt_hw_interrupt_disable();
//
//    if (serial->config.bufsz == 0)
//    {
//        int result = RT_EOK;
//        struct pt_serial_rx_dma *rx_dma;
//
//        rx_dma = (struct pt_serial_rx_dma*)serial->serial_rx;
//        PT_ASSERT(rx_dma != PT_NULL);
//
//        if (rx_dma->activated != RT_TRUE)
//        {
//            rx_dma->activated = RT_TRUE;
//            PT_ASSERT(serial->ops->dma_transmit != PT_NULL);
//            serial->ops->dma_transmit(serial, data, length, pt_serial_DMA_RX);
//        }
//        else result = -RT_EBUSY;
//        rt_hw_interrupt_enable(level);
//
//        if (result == RT_EOK) return length;
//
//        rt_set_errno(result);
//        return 0;
//    }
//    else
//    {
//        struct pt_serial_rx_fifo *rx_fifo = (struct pt_serial_rx_fifo *) serial->serial_rx;
//        uint32_t recv_len = 0, fifo_recved_len = rt_dma_calc_recved_len(serial);
//
//        PT_ASSERT(rx_fifo != PT_NULL);
//
//        if (length < fifo_recved_len)
//            recv_len = length;
//        else
//            recv_len = fifo_recved_len;
//
//        if (rx_fifo->get_index + recv_len < serial->config.bufsz)
//            rt_memcpy(data, rx_fifo->buffer + rx_fifo->get_index, recv_len);
//        else
//        {
//            rt_memcpy(data, rx_fifo->buffer + rx_fifo->get_index,
//                    serial->config.bufsz - rx_fifo->get_index);
//            rt_memcpy(data + serial->config.bufsz - rx_fifo->get_index, rx_fifo->buffer,
//                    recv_len + rx_fifo->get_index - serial->config.bufsz);
//        }
//        rt_dma_recv_update_get_index(serial, recv_len);
//        rt_hw_interrupt_enable(level);
//        return recv_len;
//    }
//}

static inline int _serial_dma_tx(struct pt_serial_device *serial, const uint8_t *data, int length)
{
    int32_t result;
    uint32_t send_len = length;
    struct serial_fifo *tx_fifo;

    tx_fifo = serial->serial_tx;
    PT_ASSERT(tx_fifo != PT_NULL);

    result = fifo_write(tx_fifo, data, &send_len);     //写入到发送fifo
	uint32_t bufsize = DMA_TX_BUF_LEN;


    if (result == PT_EOK){
        // DMA 不忙才可发送, 忙的话就等它不忙时进入中断时发送
        if ( !serial->ops->dma_busy(serial) ){ // 要写一个DMA忙状态监测的底层函数
			uint8_t *set_dma_buf = kernel_malloc(bufsize);  // 为了让接口简洁, 牺牲性能
			// 默认发DMA_TX_BUF_LEN长度, 没那么长也没关系
			if( 0 == fifo_read(tx_fifo, set_dma_buf, &bufsize) ){
				serial->ops->dma_transmit(serial, set_dma_buf, bufsize, PT_SERIAL_DMA_TX);
			}
			pt_free(set_dma_buf);
        }

        return send_len;
    }else{
        PT_DEBUG_LOG(PT_LOG_LEVEL_DEBUG, ("dma send err\n") );
        return 0;
    }
}

/* RT-Thread Device Interface */
/*
 * This function initializes serial device.
 */
static int32_t pt_serial_init(struct pt_device *dev)
{
    int32_t result = PT_EOK;
    struct pt_serial_device *serial;

    PT_ASSERT(dev != PT_NULL);
    serial = (struct pt_serial_device *)dev;

    serial->serial_rx = PT_NULL;
    serial->serial_tx = PT_NULL;

    // 调用静态赋值给串口方法的configure
    if (serial->ops->configure){
        result = serial->ops->configure(serial, &serial->config);
    }

    return result;
}


#define INIT_RX_FIFO()                                                                          \
do{                                                                                             \
    struct serial_fifo* rx_fifo;                                                                \
    rx_fifo = (struct serial_fifo*) kernel_malloc (sizeof(struct serial_fifo) +                     \
        UART_RX_FIFO_LEN);                          /*创建接收fifo, 真正的fifo_buf紧挨着分配*/  \
    PT_ASSERT(rx_fifo != PT_NULL);                                                              \
    rx_fifo->buffer = (uint8_t*) (rx_fifo + 1);     /*buf就在这片内存后*/                       \
    memset(rx_fifo->buffer, 0, UART_RX_FIFO_LEN);                                               \
    rx_fifo->buf_size = UART_RX_FIFO_LEN;                                                       \
    rx_fifo->put_index = 0;                                                                     \
    rx_fifo->get_index = 0;                                                                     \
    rx_fifo->is_full = false;                                                                   \
    serial->serial_rx = rx_fifo;                    /*将fifo挂入serial*/                        \
}while(0)

#define INIT_TX_FIFO()                                                                          \
do{                                                                                             \
    struct serial_fifo* tx_fifo;                                                                \
    tx_fifo = (struct serial_fifo*) kernel_malloc (sizeof(struct serial_fifo) +                     \
        UART_TX_FIFO_LEN);                          /*创建接收fifo, 真正的fifo_buf紧挨着分配*/  \
    PT_ASSERT(tx_fifo != PT_NULL);                                                              \
    tx_fifo->buffer = (uint8_t*) (tx_fifo + 1);     /*buf就在这片内存后*/                       \
    memset(tx_fifo->buffer, 0, UART_TX_FIFO_LEN);                                               \
    tx_fifo->buf_size = UART_TX_FIFO_LEN;                                                       \
    tx_fifo->put_index = 0;                                                                     \
    tx_fifo->get_index = 0;                                                                     \
    tx_fifo->is_full = false;                                                                   \
    serial->serial_tx = tx_fifo;                    /*将fifo挂入serial*/                        \
}while(0)

static int32_t pt_serial_open(struct pt_device *dev, uint16_t oflag)
{
    PT_ASSERT(dev != PT_NULL);
    struct pt_serial_device *serial;
    serial = (struct pt_serial_device *)dev;


    /* get open flags */
    dev->open_flag = oflag & 0xff;

     /* initialize the Rx/Tx structure according to open flag */
    if (serial->serial_rx == PT_NULL){
        if (oflag & PT_DEVICE_FLAG_DMA_RX){

            INIT_RX_FIFO();

            //以DMA模式打开串口设备
            serial->ops->control(serial, PT_DEVICE_CTRL_CONFIG, (void *) PT_DEVICE_FLAG_DMA_RX);

            dev->open_flag |= PT_DEVICE_FLAG_DMA_RX;

        }else if (oflag & PT_DEVICE_FLAG_INT_RX){

            INIT_RX_FIFO();

            dev->open_flag |= PT_DEVICE_FLAG_INT_RX;
            //以接收中断模式打开串口设备
            serial->ops->control(serial, PT_DEVICE_CTRL_SET_INT, (void *)PT_DEVICE_FLAG_INT_RX);

        }else{
            serial->serial_rx = PT_NULL;
        }
    }else{  // 已经分配过 serial_rx, 这里只进行打开操作
        if (oflag & PT_DEVICE_FLAG_DMA_RX)
            dev->open_flag |= PT_DEVICE_FLAG_DMA_RX;
        else if (oflag & PT_DEVICE_FLAG_INT_RX)
            dev->open_flag |= PT_DEVICE_FLAG_INT_RX;
    }

    if (serial->serial_tx == PT_NULL){
        if (oflag & PT_DEVICE_FLAG_DMA_TX){
            INIT_TX_FIFO();

            dev->open_flag |= PT_DEVICE_FLAG_DMA_TX;
            serial->ops->control(serial, PT_DEVICE_CTRL_CONFIG, (void *)PT_DEVICE_FLAG_DMA_TX);

        }else if (oflag & PT_DEVICE_FLAG_INT_TX){
            INIT_TX_FIFO();

            dev->open_flag |= PT_DEVICE_FLAG_INT_TX;
            serial->ops->control(serial, PT_DEVICE_CTRL_SET_INT, (void *)PT_DEVICE_FLAG_INT_TX);
        }else{
            serial->serial_tx = PT_NULL;
        }
    }else{
        if (oflag & PT_DEVICE_FLAG_DMA_TX)
            dev->open_flag |= PT_DEVICE_FLAG_DMA_TX;
        else if (oflag & PT_DEVICE_FLAG_INT_TX)
            dev->open_flag |= PT_DEVICE_FLAG_INT_TX;
    }

    return PT_EOK;
}

static int32_t pt_serial_close(struct pt_device *dev)
{
    struct pt_serial_device *serial;

    PT_ASSERT(dev != PT_NULL);
    serial = (struct pt_serial_device *)dev;
    /* this device has more reference count */
    if (dev->ref_count > 1) return PT_EOK;

    if (dev->open_flag & PT_DEVICE_FLAG_INT_RX){
        struct serial_fifo* rx_fifo;

        rx_fifo = (struct serial_fifo*)serial->serial_rx;
        PT_ASSERT(rx_fifo != PT_NULL);
        //释放掉分配的fifo
        pt_free(rx_fifo);
        serial->serial_rx = PT_NULL;
        dev->open_flag &= ~PT_DEVICE_FLAG_INT_RX;
        /* configure low level device */
        serial->ops->control(serial, PT_DEVICE_CTRL_CLR_INT, (void*)PT_DEVICE_FLAG_INT_RX);

    }else if (dev->open_flag & PT_DEVICE_FLAG_DMA_RX){

        struct serial_fifo* rx_fifo;

        rx_fifo = (struct serial_fifo*)serial->serial_rx;
        PT_ASSERT(rx_fifo != PT_NULL);

        pt_free(rx_fifo);

        /* configure low level device */
        serial->ops->control(serial, PT_DEVICE_CTRL_CLR_INT, (void *) PT_DEVICE_FLAG_DMA_RX);
        serial->serial_rx = PT_NULL;
        dev->open_flag &= ~PT_DEVICE_FLAG_DMA_RX;
    }

    if (dev->open_flag & PT_DEVICE_FLAG_INT_TX){
        struct serial_fifo* tx_fifo;

        tx_fifo = (struct serial_fifo*)serial->serial_tx;
        PT_ASSERT(tx_fifo != PT_NULL);

        pt_free(tx_fifo);
        serial->serial_tx = PT_NULL;
        dev->open_flag &= ~PT_DEVICE_FLAG_INT_TX;
        /* configure low level device */
        serial->ops->control(serial, PT_DEVICE_CTRL_CLR_INT, (void*)PT_DEVICE_FLAG_INT_TX);

    }else if (dev->open_flag & PT_DEVICE_FLAG_DMA_TX){
        struct serial_fifo* tx_fifo;

        tx_fifo = (struct serial_fifo*)serial->serial_tx;
        PT_ASSERT(tx_fifo != PT_NULL);

        pt_free(tx_fifo);
        serial->serial_tx = PT_NULL;
        dev->open_flag &= ~PT_DEVICE_FLAG_DMA_TX;
    }

    return PT_EOK;

}

static uint32_t pt_serial_read(struct pt_device *dev,
                                int32_t          pos,
                                void             *buffer,
                                uint32_t         size)
{
    (void)pos;
    struct pt_serial_device *serial;

    PT_ASSERT(dev != PT_NULL);
    if (size == 0) return 0;

    serial = (struct pt_serial_device *)dev;    //dev位于serial的头部

    struct serial_fifo *rx_fifo = serial->serial_rx;
    if(rx_fifo != PT_NULL){
        fifo_read(rx_fifo, buffer, &size);
    }else{
        size = 0;
        PT_DEBUG_LOG(PT_LOG_LEVEL_DEBUG, ("pt_serial_read no rx_fifo\n") );
    }


    // 返回真正读到的长度
    return size;
    // 这里不这么设计吧, 读就是看fifo有没有东西, 没有就退出就好了, 轮询方式不管了
    // 由pt_serial_control 控制开始接收

//    if (dev->open_flag & PT_DEVICE_FLAG_INT_RX){
//        return _serial_int_rx(serial, buffer, size);    //
//
//    }else if (dev->open_flag & PT_DEVICE_FLAG_DMA_RX){
//        return _serial_dma_rx(serial, buffer, size);
//
//    }else{
//        return _serial_poll_rx(serial, buffer, size);
//    }

}

static uint32_t pt_serial_write ( struct pt_device * dev,
								  int32_t          pos,
								  const void    *   buffer,
								  uint32_t         size )
{
	struct pt_serial_device * serial;

	PT_ASSERT ( dev != PT_NULL );

	if ( size == 0 ) {
		return 0;
	}

	serial = ( struct pt_serial_device * ) dev;
	//fifo_write(&uart_tx_fifo, p_byte_array, p_size);

	// 根据打开方式调用不同的底层
	if ( dev->open_flag & PT_DEVICE_FLAG_INT_TX ) {         //发送完一个字节就中断一次
		return _serial_int_tx ( serial, buffer, 1 );

	} else if ( dev->open_flag & PT_DEVICE_FLAG_DMA_TX ) {
		return _serial_dma_tx ( serial, buffer, size );

	} else {
		return _serial_poll_tx ( serial, buffer, size );
	}

}

static int32_t pt_serial_control(struct pt_device *dev,
                                  int              cmd,
                                  void             *args)
{
    int32_t ret = PT_EOK;
    struct pt_serial_device *serial;

    PT_ASSERT(dev != PT_NULL);
    serial = (struct pt_serial_device *)dev;

    switch (cmd)
    {
        case PT_DEVICE_CTRL_SUSPEND:
            /* suspend device */
            dev->flag |= PT_DEVICE_FLAG_SUSPENDED;
            break;

        case PT_DEVICE_CTRL_RESUME:
            /* resume device */
            dev->flag &= ~PT_DEVICE_FLAG_SUSPENDED;
            break;

        case PT_DEVICE_CTRL_CONFIG:
            if (args){

                struct serial_configure *pconfig = (struct serial_configure *) args;

                /* set serial configure */
                serial->config = *pconfig;
                if (serial->parent.ref_count){
                    /* serial device has been opened, to configure it */
                    serial->ops->configure(serial, (struct serial_configure *) args);
                }
            }

            break;

        default :
            /* control device */
            ret = serial->ops->control(serial, cmd, args);
            break;
    }

    return ret;
}

/*
 * serial register
 */
int32_t pt_hw_serial_register(struct pt_serial_device *serial,
                               uint8_t              device_id,
                               uint32_t              flag,
                               void                    *data)
{
    int32_t ret;
    struct pt_device *device;
    PT_ASSERT(serial != PT_NULL);

    device = &(serial->parent);

    device->type        = PT_Device_Class_Char;
    device->rx_indicate = PT_NULL;              // 默认无回调
    device->tx_complete = PT_NULL;

    device->init        = pt_serial_init;
    device->open        = pt_serial_open;
    device->close       = pt_serial_close;
    device->read        = pt_serial_read;
    device->write       = pt_serial_write;
    device->control     = pt_serial_control;

    device->user_data   = data;

    /* register a character device */
//    ret = pt_device_register(device, name, flag);
    //不用name, 用device_id
    ret = pt_device_register(device, device_id, flag);

//	pt_device_register ( &_hw_pin.parent, device_id, PT_DEVICE_FLAG_RDWR );
    return ret;
}

/* ISR for serial interrupt */
void pt_hw_serial_isr ( struct pt_serial_device * serial, uint8_t event, uint16_t len )
{
	struct pt_device * device = &serial->parent;


	switch ( event ) {
		case PT_SERIAL_EVENT_RX_IND: {
            struct serial_fifo * rx_fifo;
            rx_fifo = ( struct serial_fifo * ) serial->serial_rx;
			// 未以中断接收方式打开了设备, 则退出
			if ( ! ( device->open_flag & PT_DEVICE_FLAG_INT_RX ) ) {
				PT_DEBUG_LOG ( PT_LOG_LEVEL_DEBUG, ( "not open with int rx\n" ) );
				break;
			}

			int ch = -1;

			if ( rx_fifo != PT_NULL ) {
				while ( 1 ) {
					ch = serial->ops->getc ( serial );

					if ( ch == -1 ) {
						break;
					}

					fifo_put ( rx_fifo, ch );
				}

				// 调用应用程序注册的回调函数
				if ( serial->parent.rx_indicate != PT_NULL ) {
					uint32_t rx_length;

					rx_length = fifo_length ( rx_fifo );
					serial->parent.rx_indicate ( &serial->parent, rx_length );
				}

			} else {
				PT_DEBUG_LOG ( PT_LOG_LEVEL_DEBUG, ( "RX_IND no rx_fifo\n" ) );
			}

			break;
		}

		case PT_SERIAL_EVENT_TX_DONE: {
            struct serial_fifo * tx_fifo;
            tx_fifo = ( struct serial_fifo * ) serial->serial_tx;

			// 未以中断发送方式打开了设备, 则退出
			if ( ! ( device->open_flag & PT_DEVICE_FLAG_INT_TX ) ) {
				PT_DEBUG_LOG ( PT_LOG_LEVEL_DEBUG, ( "not open with int tx\n" ) );
				break;
			}

            uint8_t ch = 0;
            if( PT_EOK == fifo_get(tx_fifo, &ch) ){
                _serial_int_tx ( serial, tx_fifo->buffer, 1 );  // 一次只能发一个
            }else{
                // fifo 发空了, 调用应用回调, 通知发送完毕
                if ( serial->parent.tx_complete != PT_NULL ) {
                    serial->parent.tx_complete ( &serial->parent, ( void * ) PT_NULL );
                }
            }

			break;
		}

		case PT_SERIAL_EVENT_TX_DMADONE: {
            struct serial_fifo * tx_fifo;
            tx_fifo = ( struct serial_fifo * ) serial->serial_tx;

			// 未以DMA发送方式打开了设备, 则退出
			if ( ! ( device->open_flag & PT_DEVICE_FLAG_DMA_TX ) ) {
				PT_DEBUG_LOG ( PT_LOG_LEVEL_DEBUG, ( "not open with dma tx\n" ) );
				break;
			}


			uint32_t bufsize = DMA_TX_BUF_LEN;
			uint8_t *set_dma_buf = kernel_malloc(bufsize);  // 为了让接口简洁, 牺牲性能

            // 如果有数据就继续发, 到这里, DMA已经退出忙状态了, 因为都发完进入中断了
            // 默认发DMA_TX_BUF_LEN长度, 没那么长也没关系
            if( 0 == fifo_read(tx_fifo, set_dma_buf, &bufsize) ){
                serial->ops->dma_transmit(serial, set_dma_buf, bufsize, PT_SERIAL_DMA_TX);
            }

			pt_free(set_dma_buf);

			/* invoke callback */
			if ( serial->parent.tx_complete != PT_NULL ) {
				serial->parent.tx_complete ( &serial->parent, ( void * ) PT_NULL );
			}

			break;
		}

		case PT_SERIAL_EVENT_RX_DMADONE: {
            struct serial_fifo * rx_fifo;
            rx_fifo = ( struct serial_fifo * ) serial->serial_rx;
			// 未以DMA方式打开了设备, 则退出
			if ( ! ( device->open_flag & PT_DEVICE_FLAG_DMA_RX ) ) {
				PT_DEBUG_LOG ( PT_LOG_LEVEL_DEBUG, ( "not open with dma rx\n" ) );
				break;
			}

			if ( rx_fifo != PT_NULL ) {
				// 长度len指示了DMA接收到了多少个字节
				uint8_t bufsize = serial->config.rx_fifo_sz;
				uint8_t *get_dma_buf = kernel_malloc(bufsize);  // 为了让接口简洁, 牺牲性能

				//从DMA缓存中获取到 get_dma_buf 中
				PT_ASSERT(serial->ops->dma_transmit != PT_NULL);
				serial->ops->dma_transmit(serial, get_dma_buf, len, PT_SERIAL_DMA_RX);
				// 再从这个buf转移到fifo中
				uint32_t write_len = len;
				fifo_write(rx_fifo, get_dma_buf, &write_len);
				pt_free(get_dma_buf);       //注意释放, 用静态更安全一些

				/* invoke callback */
				if ( serial->parent.rx_indicate != PT_NULL ) {
					serial->parent.rx_indicate ( & ( serial->parent ), len );
				}

			} else {
				PT_DEBUG_LOG ( PT_LOG_LEVEL_DEBUG, ( "RX_DMA no rx_fifo\n" ) );
			}


			break;
		}
	}
}



#include <stdarg.h>
#include <string.h>

static uint8_t printf_use_device_id = PT_NULL;
void set_printf_use_device_id(uint8_t id)
{
	printf_use_device_id = id;
}
void app_printf ( const char * fmt, ... )
{
	#define PRINTF_MAX	128
	static char app_printf_buf[PRINTF_MAX];

	// 需要先设置printf使用的设备ID
	if(PT_NULL == printf_use_device_id){
		return;
	}
	//定义指针vlist

	va_list vlist;
	//让vlist指向形参的第一个变量
	va_start ( vlist, fmt );
	//把fmt和不定长的参数（vlist指向参数列表）复制到debug_buffer中

	vsnprintf( app_printf_buf, PRINTF_MAX, fmt, vlist );

	uint32_t send_len = 0;
	send_len = strlen ( app_printf_buf );

//	app_uart_write( (uint8_t *)app_printf_buf, &send_len);

	pt_device_t usart_dev;

	usart_dev = pt_device_find(printf_use_device_id);    //找到设备
	pt_serial_write( usart_dev, 0, app_printf_buf, send_len);

	//在使用完指针之后，需要把指针关掉，以防出现危险。
	va_end ( vlist );

}


